package com.rem.redis;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import com.rem.redis.config.BloomFilterHelper;
import com.rem.redis.config.RedisBloomFilter;
import org.junit.jupiter.api.Test;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.IntegerCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 测试布隆过滤器
 *
 * @author Rem
 * @date 2022-05-24
 */

@SpringBootTest
public class Redis11BloomFilter {

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    RedisBloomFilter redisBloomFilter;

    Double fpp = 0.02;
    Integer expectedInsertions = 1000000;


    /**
     * 创建一个具有预期插入次数和预期误报概率的BloomFilter 。
     * 请注意，溢出的元素比指定的多得多的BloomFilter将导致其饱和，并导致其误报概率急剧恶化。
     * 如果提供的Funnel<T>是，则构造的BloomFilter将是可序列化的。
     * 建议将funnel实现为 Java 枚举。这有利于确保正确的序列化和反序列化，这很重要，因为equals还依赖于漏斗的对象标识。
     * <p>
     * <p>
     * funnel – 构造的BloomFilter将使用的 T 的漏斗
     * expectedInsertions – 构造的BloomFilter的预期插入次数；必须是正面的
     * fpp – 期望的误报概率（必须为正且小于 1.0）
     */
    @Test
    void guavaBloomFilter() {
        BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), expectedInsertions, fpp);
        for (int i = 0; i < expectedInsertions; i++) {
            bloomFilter.put(i);
        }

        int count = 0;
        for (int i = expectedInsertions; i < expectedInsertions * 2; i++) {
            if (bloomFilter.mightContain(i)) {
                count++;
            }
        }
        System.out.println("一共误判了：" + count);
    }

    /**
     * 使用redission带的布隆过滤器
     */
    @Test
    void RedissionBloomFilter() {
        expectedInsertions = 500;
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("redission01", IntegerCodec.INSTANCE);
        bloomFilter.tryInit(expectedInsertions, fpp);
        for (int i = 0; i < expectedInsertions; i++) {
            bloomFilter.add(i);
        }

        int count = 0;
        for (int i = expectedInsertions; i < expectedInsertions * 2; i++) {
            if (bloomFilter.contains(i)) {
                count++;
            }
        }
        System.out.println("一共误判了：" + count);
    }

    /**
     * 使用redis bitField原生做布隆过滤器
     */
    @Test
    void RedisBloomFilter() {
        expectedInsertions = 500;
        BloomFilterHelper<Integer> integerBloomFilterHelper = new BloomFilterHelper<>(Funnels.integerFunnel(), expectedInsertions, fpp);

        for (int i = 0; i < expectedInsertions; i++) {
            redisBloomFilter.addByBloomFilter(integerBloomFilterHelper, "redis05", i);
        }

        int count = 0;
        for (int i = expectedInsertions; i < expectedInsertions * 2; i++) {
            if (redisBloomFilter.includeByBloomFilter(integerBloomFilterHelper, "redis05", i)) {
                count++;
            }
        }
        System.out.println("一共误判了：" + count);
    }

    /**
     * 使用redis bitField原生做布隆过滤器
     */
    @Test
    void RedisBloomFilter2() {
        expectedInsertions = 500;
        BloomFilterHelper<Integer> integerBloomFilterHelper = new BloomFilterHelper<>(Funnels.integerFunnel(), expectedInsertions, fpp);


        if (redisBloomFilter.includeByBloomFilter(integerBloomFilterHelper, "redis05", 2)) {
            System.out.println("一共误判了：" + 1);
        }

    }


}
